#ifndef LEXER_HEAD
#define LEXER_HEAD
//词法分析头文件
/*
包含读入算法scan和类lexer
create at 2024.1.31 by zhywyt
*/
#include <iostream>
#include <algorithm>
#include <map>
#include <vector>

#include "Token.hpp"
#include "Word.hpp"
#include "Num.hpp"
#include "Tag.hpp"

using std::map;
using std::string;

class lexer{
public:
    inline void reserve(Word t){
        words[t.lexme()] = t;
    }
    lexer():line(1),peek(' '){
        reserve(Word(Tag::TRUE,"true"));
        reserve(Word(Tag::FALSE,"flase"));
    }
    Token scan(){
        std::cout<<"in scan"<<std::endl;
        for(;;peek = getchar()){
            if(peek == ' '||peek == '\t')continue;
            else if(peek == '\n')line++;
            else break;
        }
        if(isDigit(peek)){
            int v = 0;
            do{
                v = v<<2+v<<1+peek - '0';
                peek = getchar();
            }while(isDigit(peek));
            return Num(v);
        }
        else if(isLetter(peek)){
            string b;
            do{
                b = b + peek;
                peek = getchar();
            }while(isDigit(peek)||isLetter(peek));
            if(!words.count(b))words[b]=Word(Tag::ID,b);
            return words[b];
        }
        else if(peek == '/'){
            comment();
            return scan();
        }
        Token t(peek);
        peek = ' ';
        return t;
    }
    void showLexer(){
        std::cout<<"--------------------Lexer Wrods--------------------"<<std::endl;
        for(auto& i:words){
            std::cout<<i.first<<" : "<<i.second.tag()<<", ";
        }
        std::cout<<std::endl;
        std::cout<<"--------------------Lexer Lines--------------------"<<std::endl;
        std::cout<<"lines : "<<line<<std::endl;
    }
private:
    inline bool isDigit(const char& c){
        return c>='0'&&c<='9';
    }
    inline bool isLetter(const char&c){
        return (c>='a'&&c<='z')||(c>='A'&&c<='Z');
    }
    void comment(){
        peek = getchar();
        if(peek == '/')line_comment();
        else if(peek == '*')block_comment();
        else{
            std::cout<<"peek:"<<peek<<std::endl;
            throw("Comment Syntax Error!");
        }
    }
    void line_comment(){    
        while((peek = getchar())!='\n'&&peek!=EOF);
        if(peek==EOF)throw("Line Comment Syntax Error!");
        line++;
    }
    void block_comment(){
        do{
            peek = getchar();
            if(peek == '\n')line++;
        }while(peek!='*'&&peek != EOF);
        if(peek == '*')block_commen_star();
        else throw("Block Comment Synatax Error!");
    }
    void block_commen_star(){//input a star when scan block comment
        peek = getchar();
        if(peek == '/'){
            peek = ' ';
            return;
        }
        else block_comment();
    }
    int line;
    char peek;
    map<string,Word>words;
};
#endif